import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAException;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import java.util.StringTokenizer;

public class SendAgent extends Agent
{
  protected Container [] Senders;
  protected String bpName;
  protected String here;
  protected boolean doneSent;
  protected int curr_time;
  protected int maxX;
  protected int maxY;
  protected int maxZ;
  protected int time_stamp;
  protected int totalContainers;
  
  public void setup()
  {
    here = here().getName();
    System.out.println("Send Agent at " + here().getName());
    DFAgentDescription dfd = new DFAgentDescription();
    dfd.setName(getAID());
    ServiceDescription sd = new ServiceDescription();
    sd.setType("Message-sending");
    sd.setName(getLocalName()+"-Message-sending");
    dfd.addServices(sd);
    try
    {
      DFService.register(this, dfd);
    }
    catch (FIPAException fe)
    {
      fe.printStackTrace();
    }
    addBehaviour( new CyclicBehaviour()
    {
      public void action()
      {
        MessageTemplate tmp = MessageTemplate.MatchOntology("Container-start" +
          "-ontology");
        ACLMessage firstMsg = receive(tmp);
        if (firstMsg != null)
        {

          StringTokenizer st = new StringTokenizer(firstMsg.getContent(),":");

          maxX = Integer.parseInt(st.nextToken());
          maxY = Integer.parseInt(st.nextToken());
          maxZ = Integer.parseInt(st.nextToken());
          totalContainers = Integer.parseInt(st.nextToken());
          bpName = st.nextToken();
          time_stamp = Integer.parseInt(st.nextToken());
          Senders = new Container[maxX * maxY * maxZ];
          for (int i = 0; i < Senders.length; i++)
          {
            int iClone = i;
            int locz = iClone%maxZ;
            iClone /= maxZ;
            int locx = iClone%maxX;
            iClone /= maxX;
            int locy = iClone;
            Senders[i] = new Container("Container_" + here + "_" + i, locx,
                locy, locz, 0, Math.round(Math.random()*90), 90L, false, false);
          }
          System.out.println("Made it this far!");
          addBehaviour( new CyclicBehaviour()
          {
            public void action()
            {
              Cycle();
              CheckMessages();
            }
          });
        
          removeBehaviour(this);
        } 
      
        else
        {
          block();
        }
      }
    });

      }
  private void Cycle()
  {
    //System.out.println(curr_time + " " + time_stamp);
    if (curr_time < time_stamp)
    {
      doneSent = false;
      for (int i = 0; i < Senders.length; i++)
      {
        process(Senders[i]);
      }
      curr_time++;
    }
    else if (curr_time == time_stamp && !doneSent)
    {
      ACLMessage doneMsg = new ACLMessage(ACLMessage.INFORM);
      doneMsg.addReceiver(new AID("local_" + here, AID.ISLOCALNAME));
      doneMsg.setLanguage("English");
      doneMsg.setOntology("Container-continue-ontology");
      doneMsg.setContent("Done");
      send(doneMsg);
      doneSent = true;
    }

  }

  private void CheckMessages()
  {

    ACLMessage msgRX = receive();
    while (msgRX != null)
    {
      process(msgRX);
      msgRX = receive();
    }
  }

  private void process(Container obj)
  {
    if (obj != null)
    {

      obj.processEnvAndState();
      while(obj.TXindex >= 0)
      {
        ACLMessage containerMsg = new ACLMessage(ACLMessage.INFORM);
        containerMsg.addReceiver(new AID("Receive_" + here().getName() + "_" +
              bpName, AID.ISLOCALNAME));
        containerMsg.setLanguage("English");
        containerMsg.setOntology("Container-message-ontology");
        containerMsg.setContent(obj.location[0] + "|" + obj.location[1] + "|" +
            obj.location[2] + "|" + (obj.sendMessage()).toMessage("%"));
        send(containerMsg);
       
        //System.out.println(containerMsg);
        //Do this for all the messages in that crate's stack? Or just one?
        //If multiple, this needs to be in a while(obj.TXindex >= 0)
      }
      obj.incrementClock();
      if (obj.CLOCK_TIME % obj.CYCLE_LENGTH > obj.SEND_TIME)
      {
        ACLMessage containerMsg = new ACLMessage(ACLMessage.INFORM);
        containerMsg.addReceiver(new AID("Receive_" + here().getName() + "_" +
              bpName, AID.ISLOCALNAME));
        containerMsg.setLanguage("English");
        containerMsg.setOntology("Container-delivery-ontology");
        containerMsg.setContent(obj.toMessage("|"));
        send(containerMsg);
        Senders[(maxZ*(maxX*obj.location[1] + obj.location[0]) +
            obj.location[2])] = null;
      }
    }
  }

  private void process(ACLMessage msg)
  {
    MessageTemplate tmp = MessageTemplate.MatchOntology("Container-continue-" +
        "-ontology");
    ACLMessage rcv = receive(tmp);
    if (rcv != null)
    {
      time_stamp = Integer.parseInt(rcv.getContent());
    }

  }

  //Any further functions that the SendAgent needs to do will go here.
}


